#include "Multigrid.h"
#include "json.hpp"

#define exp 2.718281828

int epInd1 = 0;
int epInd2 = 0;

int t = 0;

// 计算误差并汇报信息
template <int dim>
void plot(Grid<dim> &gData, Container2D &U, Container2D &V, Container2D &EX, int times, Real *residual, double t1, double t2)
{
    // 汇报迭代次数
    t = times;
    cout << times << endl;
}

// 计算函数
template <int dim>
void calculateOne(json &inputs, MultiSolver<dim> &ms)
{
    // 读取数据的总量
    int num = inputs["Num"];

    // 逐个计算
    for (int i = 0; i < num; i++)
    {
        // 当前数据
        json nj = inputs["Data"][i];

        cout << endl;

        int n = 32;
        int p = 4;

        for (int j = 0; j < p; j++)
        {
            cout << "n = " << n << endl;

            // 记录规模
            ms.gData.n = n;

            // 使用无穷范数
            int norm = 0;

            // 读取边界数据
            ms.read(nj);

            // 绘制迭代曲线
            cout << "I = [\n";
            while (ms.epsilon > 1e-16)
            {
                cout << ms.epsilon << " ";
                ms.multiSolve(norm, plot);
                ms.epsilon /= 10;
            }
            cout << "];" << endl;

            cout << "plot(log10(I(:,1)),I(:,2),'-', 'MarkerSize', 5);" << endl;
            cout << "hold on;" << endl;
            cout << endl;

            n *= 2;
        }

        cout << "legend('32', '64', '128', '256');" << endl;
        cout << "xlabel('epsilon');" << endl;
        cout << "ylabel('iteration times');" << endl;
        cout << "saveas(gcf,'oneEpInd" << ++epInd1 << ".png');" << endl;
        cout << "clf;" << endl;

        cout << endl;
    }
}

// 计算函数
template <int dim>
void calculateTwo(json &inputs, MultiSolver<dim> &ms)
{
    // 读取数据的总量
    int num = inputs["Num"];

    // 逐个计算
    for (int i = 0; i < num; i++)
    {
        // 当前数据
        json nj = inputs["Data"][i];

        cout << endl;

        int n = 4;
        int p = 4;

        for (int j = 0; j < p; j++)
        {
            cout << "n = " << n << endl;

            // 记录规模
            ms.gData.n = n;

            // 使用无穷范数
            int norm = 0;

            // 读取边界数据
            ms.read(nj);

            // 绘制迭代曲线
            t = 0;
            cout << "I = [\n";
            while (ms.epsilon > 1e-16 && t < 100)
            {
                cout << ms.epsilon << " ";
                ms.multiSolve(norm, plot);
                ms.epsilon /= 10;
            }
            cout << "];" << endl;

            cout << "plot(log10(I(:,1)),I(:,2),'-', 'MarkerSize', 5);" << endl;
            cout << "hold on;" << endl;
            cout << endl;

            n *= 2;
        }

        cout << "legend('4', '8', '16', '32');" << endl;
        cout << "xlabel('epsilon');" << endl;
        cout << "ylabel('iteration times');" << endl;
        cout << "saveas(gcf,'twoEpInd" << ++epInd2 << ".png');" << endl;
        cout << "clf;" << endl;

        cout << endl;
    }
}

void testOne(json &inputs)
{
    Func<1> u = [](Point<1> p)
    {
        Real x = p[0];
        return pow(exp, x);
    };

    Func<1> ux = [](Point<1> p)
    {
        Real x = p[0];
        return pow(exp, x);
    };

    Func<1> f = [](Point<1> p)
    {
        Real x = p[0];
        return -pow(exp, x);
    };

    MultiSolver<1> ms;

    // 函数
    ms.gData.f = f;
    ms.gData.u = u;
    ms.gData.du[0] = ux;

    calculateOne(inputs, ms);
}

void testTwo(json &inputs)
{
    Func<2> u = [](Point<2> p)
    {
        Real x = p[0];
        Real y = p[1];
        return pow(exp, y + sin(x));
    };

    Func<2> ux = [](Point<2> p)
    {
        Real x = p[0];
        Real y = p[1];
        return pow(exp, y + sin(x)) * cos(x);
    };

    Func<2> uy = [](Point<2> p)
    {
        Real x = p[0];
        Real y = p[1];
        return pow(exp, y + sin(x));
    };

    Func<2> f = [](Point<2> p)
    {
        Real x = p[0];
        Real y = p[1];
        return -pow(exp, y + sin(x)) * (1 + cos(x) * cos(x) - sin(x));
    };

    MultiSolver<2> ms;

    // 函数
    ms.gData.f = f;
    ms.gData.u = u;
    ms.gData.du[0] = ux;
    ms.gData.du[1] = uy;

    calculateTwo(inputs, ms);
}

int main()
{
    fstream fp("draw.json", ios::in);
    json inputs;
    fp >> inputs;

    cout << endl;
    testOne(inputs);

    cout << endl;
    testTwo(inputs);

    return 0;
}